package org.bud.db.dynamic.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.bud.db.dynamic.base.DynamicDataSource;
import org.bud.db.dynamic.base.DynamicVSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author shaun
 * @date 2025/4/1
 * @instruction
 */
public class DynamicDataSourceConfig {
    @Bean
    public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    @Bean
    public DynamicDataSource dynamicDataSource(List<DynamicVSource> dvSources){
        HashMap<Object, Object> targetDataSources = dvSources.stream()
                .collect(HashMap::new, (all, o) -> all.put(o.getDbKey(), o), Map::putAll);
        Object defaultTargetDataSource = targetDataSources.values().stream()
                .filter(o -> ((DynamicVSource)o).isDefaultDb()).findFirst()
                .orElseThrow(() -> new IllegalArgumentException("dynamic data source need set one default db"));
        DynamicDataSource dynamicDataSource = new DynamicDataSource(
                targetDataSources,defaultTargetDataSource);
        return dynamicDataSource;
    }

    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
    public MybatisProperties mybatisProperties(){
        return new MybatisProperties();
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(MybatisProperties mybatisProperties, DynamicDataSource dynamicDataSource,ResourceLoader resourceLoader) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dynamicDataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(mybatisProperties.getConfigLocation())) {
            factory.setConfigLocation(resourceLoader.getResource(mybatisProperties.getConfigLocation()));
        }
        if (!ObjectUtils.isEmpty(mybatisProperties.resolveMapperLocations())) {
            factory.setMapperLocations(mybatisProperties.resolveMapperLocations());
        }
        applyConfiguration(factory,mybatisProperties);
        if (mybatisProperties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(mybatisProperties.getConfigurationProperties());
        }
        return factory.getObject();
    }
    private void applyConfiguration(SqlSessionFactoryBean factory,MybatisProperties properties) {
        org.apache.ibatis.session.Configuration configuration = properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(properties.getConfigLocation())) {
            configuration = new org.apache.ibatis.session.Configuration();
        }
        factory.setConfiguration(configuration);
    }

}
